package bll

import (
	"context"
	"fmt"
	"go-micro.dev/v4/util/addr"
	log "signal/collector/logger"
	"signal/lib/trace_log"
	"signal/store/redis"
	"sync"
	"sync/atomic"
)

const (
	OnlineRedisKey   = "signal:online"
	ServiceOnlineKey = "signal:service"
	RpcPort          = "7775"
)

var (
	Device = &device{}
)

// 记录设备上下线状态
type device struct {
	ip           string
	host         string
	onlineMap    sync.Map
	isStopServer atomic.Bool
}

func (d *device) init() func() {
	d.ServiceStart("0.0.0.0")
	return func() {
		d.ServiceStop()
	}
}

func (d *device) ServiceStart(host string) error {
	address, err := addr.Extract(host)
	if err != nil {
		panic(err)
	}
	d.host = fmt.Sprintf("%v:%v", address, RpcPort)
	d.ip = address
	d.onlineMap = sync.Map{}
	// 清理在线设备
	redis.KV.Del(context.Background(), d.serviceRedisKey())
	log.Info("device service start")
	return nil
}

func (d *device) ServiceStop() error {
	log.Info("device service stop")
	d.isStopServer.Store(true)
	// 清理在线设备
	var sns []string
	valueMap, _ := redis.KV.HGetAll(context.Background(), d.serviceRedisKey()).Result()
	if valueMap != nil {
		for k, _ := range valueMap {
			sns = append(sns, k)
		}
	}
	trace_log.CommonLogger.Info("device service stop length:", len(sns), "sns:", sns)
	if len(sns) > 0 {
		redis.KV.HDel(context.Background(), OnlineRedisKey, sns...)
		redis.KV.Del(context.Background(), d.serviceRedisKey())
	}
	d.onlineMap = sync.Map{}
	return nil
}

// Online 设备上线
func (d *device) Online(sn string) error {
	if d.isStopServer.Load() {
		return nil
	}
	trace_log.CommonLogger.Info("device service Online sn:", sn)
	_, err := redis.KV.HSet(context.Background(), OnlineRedisKey, sn, d.host).Result()
	d.onlineMap.Store(sn, d.host)
	redis.KV.HSet(context.Background(), d.serviceRedisKey(), sn, d.host)
	return err
}

// Offline 设备下线
func (d *device) Offline(sn string) error {
	if d.isStopServer.Load() {
		return nil
	}
	trace_log.CommonLogger.Info("device service Offline sn:", sn)
	_, err := redis.KV.HDel(context.Background(), OnlineRedisKey, sn).Result()
	d.onlineMap.Delete(sn)
	redis.KV.HDel(context.Background(), d.serviceRedisKey(), sn)
	return err
}

// IsOnline 设备是否在线
func (d *device) IsOnline(sn string) bool {
	if _, ok := d.onlineMap.Load(sn); ok {
		return true
	}
	return false
}

func (d *device) serviceRedisKey() string {
	return fmt.Sprintf("%v:%v", ServiceOnlineKey, d.ip)
}
